<?php
namespace Pinenut\Context;

/**
 * Объект, реализующий интерфейс доступа к данным пользователя, сделавшего запрос
 * Работает в контексте запроса, использует сессию
 * Через него происходит аутентификация (логин) и авторизация (определение привилегий)
 * 
 * 
 * @author Kosh
 *
 */

class Auth {
	
	
	/**
	 * список привилегий, которыми обладает пользователь
	 * и ключ и значение - привилегии для быстрого поиска
	 * @var array()
	 */
	protected $privileges = null;
	
	/**
	 * Список
	 * @var unknown_type
	 */
	protected $asserts = array();
	
	/**
	 * ничего не делаем, всё надо делать лениво, 
	 * вдруг страничка формируется вообще без оглядки на пользователя 
	 * и его права
	 */
	function __construct() {
	}
	
	
	/**
	 * Проверка прав доступа
	 * 
	 * 
	 * @param string|array $privileges
	 * @return bool
	 */
	function checkAccess($privileges) {
		// инициируем список привилегий
		$this->preparePrivileges();

		//print_r($this->privileges); exit;
		// делаем однозначным массив привилегий
		$privileges = (array)$privileges;
		// для каждой привилегии проверяем её наличие в списке пользователя, 
		// если находим и утверждения верны - говорим что дуступ есть
		foreach ($privileges as $key=>$value) {
			// если только значение (ключ- индекс), то просто проверяем наличие
			if (is_int($key)) {
				if (isset($this->privileges[$value])) return true;
			} else {
				// сложная привилегия с утверждением(-ями)
				if (isset($this->privileges[$key])) {
					$value = (array)$value;
					$result = true;
					foreach ($value as $assert=>$params) {
						// если утвеждение ложно - привилегия ложна
						if (!$this->checkAssert($assert, $params)) {
							$result = false;
							break;	
						}
					}
					// если все утверждения верны - привилегия подходит, доступ разрешен
					if ($result) return true;
				}
			}
			
		}
		// ничего не нашли - доступ запрещен
		return false;
	}
	
	/**
	 * Готовим привилегии пользователя, если необходимо
	 * 
	 * 1) Проверяем сессию - если там пусто - считаем, 
	 * 		что это аноним и подгружаем привилегии для анонима
	 * 		Это делается для того, чтобы не хранить в сессии лишнего
	 * 2) Если - пользователь аутентифицирован - у него должны быть 
	 * 		установлены при этом роли, и время жизни, до очередной проверки ролей
	 * 
	 */
	function preparePrivileges() {
		// привилегии уже инициированы?
		if (null !== $this->privileges)
			return;	
	
		// устанавливаем привилегии для ауторизованного или не ауторизованного пользователя
		if ($this->isAuthorized()) {
			$this->privileges = \PrivilegesConfig::getPrivilegesByProperty('authorized');
			// подменяем звездочку на идентификатор пользователя
			$this->implementIdentityToPrivileges();
		} else {
			$this->privileges = \PrivilegesConfig::getPrivilegesByProperty('unauthorized');
		}
	}
	
	/**
	 * Внедряем в привилегии идентификатор пользователя для возможности 
	 * декларировать персональные привилегии
	 */
	function implementIdentityToPrivileges() {
		$privileges = [];
		$identity = $this->identity();
		foreach ($this->privileges as $key=>$val) {
			if (is_int($key)) {
				$privileges[] = str_replace('*', $identity, $val);
			} else {
				$privileges[str_replace('*', $identity, $key)] = $val;
			}
		}
		$this->privileges = $privileges;
	}
	
	function isAuthorized() {
		return isset($_SESSION['identity']);
	}

	function identity() {
		return isset($_SESSION['identity'])?$_SESSION['identity']:null;
	}
	
	/**
	 * Аутентификация пользователя
	 * @param unknown $user
	 */
	function login($identity, array $authData = []) {
		$_SESSION['identity'] = $identity;
		$this->authData($authData);
	}
	
	
	function logout() {
		unset($_SESSION['identity']);
		$this->authData([]);
	}
	
	/**
	 * Обёртка на установку параметров
	 * @param array $data
	 */
	function authData(array $data = null) {
		if (!isset($_SESSION['authData'])) {
			$_SESSION['authData'] = [];
		}
		if (null !== $data) {
			foreach ($data as $k=>$v) {
				$_SESSION['authData'][$k] = $v; 
			}
		}
		return $_SESSION['authData'];
	}

}